package com.example.campus.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.example.campus.exception.ImageNullException;
import com.example.campus.exception.PermissionsExceededException;
import com.example.campus.exception.QueryFailedException;
import com.example.campus.mapper.*;
import com.example.campus.pojo.dto.InfoPageQueryDTO;
import com.example.campus.pojo.dto.InfoPublishDTO;
import com.example.campus.pojo.dto.InfoUpdateDTO;
import com.example.campus.pojo.entity.Category;
import com.example.campus.pojo.entity.LostAndFoundInfo;
import com.example.campus.pojo.entity.User;
import com.example.campus.pojo.vo.LostAndFoundInfoDetailVO;
import com.example.campus.pojo.vo.LostAndFoundInfoVO;
import com.example.campus.result.PageResult;
import com.example.campus.service.LostAndFoundInfoService;
import com.example.campus.utils.constant.MessageConstant;
import com.example.campus.utils.constant.RedisConstant;
import com.example.campus.utils.constant.StatusConstant;
import com.example.campus.utils.context.BaseContext;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class LostAndFoundInfoServiceImpl implements LostAndFoundInfoService {

    @Autowired
    private LostAndFoundInfoMapper lostAndFoundInfoMapper;

    @Autowired
    private InfoCateLinkMapper infoCateLinkMapper;

    @Autowired
    private ImageMapper imageMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private CommentMapper commentMapper;

    @Autowired
    private LikeMapper likeMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public PageResult getInfoList(InfoPageQueryDTO infoPageQueryDTO) {
        PageHelper.startPage(infoPageQueryDTO.getPage(), infoPageQueryDTO.getPageSize());
        Page<LostAndFoundInfoVO> page = lostAndFoundInfoMapper.getInfoList(infoPageQueryDTO);
        for (LostAndFoundInfoVO info : page) {
            info.setCategories(infoCateLinkMapper.getByInfoId(info.getId()));
            List<String> list = imageMapper.getUrlByInfoId(info.getId());
            if (list != null && !list.isEmpty()) {
                info.setFirst_image(list.get(0));
            }
        }
        long total = page.getTotal();
        if (total < 1) {
            throw new QueryFailedException(MessageConstant.QUERY_NULL);
        }
        List<LostAndFoundInfoVO> records = page.getResult();
        return new PageResult(total, records);
    }
    /**
     * 用户发布失物或拾物信息
     * @param infoPublishDTO
     */
    @Override
    @Transactional
    public void publish(InfoPublishDTO infoPublishDTO) {
        List<String> imageUrls = infoPublishDTO.getImageUrls();
        if (imageUrls == null || imageUrls.isEmpty()) {
            throw new ImageNullException(MessageConstant.IMAGE_NULL);
        }
        LostAndFoundInfo info = new LostAndFoundInfo();
        BeanUtils.copyProperties(infoPublishDTO, info);
        info.setUserId(BaseContext.getCurrentId());
        info.setStatus(StatusConstant.UNRESOLVED);
        info.setCreateTime(LocalDateTime.now());
        info.setUpdateTime(LocalDateTime.now());
        lostAndFoundInfoMapper.insert(info);

        Long infoId = info.getId();
        List<Long> categoryIds = infoPublishDTO.getCategoryIds();
        if (categoryIds != null && !categoryIds.isEmpty()) {
            //插入分类
            infoCateLinkMapper.insertBatch(infoId, categoryIds);
        }

        imageMapper.insertBatch(infoId, imageUrls);
    }

    /**
     * 用户修改失物或拾物信息
     * @param infoUpdateDTO
     */
    @Override
    @Transactional
    public void update(InfoUpdateDTO infoUpdateDTO) {
        List<String> imageUrls = infoUpdateDTO.getImageUrls();
        if (imageUrls == null || imageUrls.isEmpty()) {
            throw new ImageNullException(MessageConstant.IMAGE_NULL);
        }
        LostAndFoundInfo info = new LostAndFoundInfo();
        BeanUtils.copyProperties(infoUpdateDTO, info);
        info.setUserId(BaseContext.getCurrentId());
        info.setUpdateTime(LocalDateTime.now());
        lostAndFoundInfoMapper.update(info);

        Long infoId = infoUpdateDTO.getId();

        //修改关联分类：先删除所有分类再重新插入
        infoCateLinkMapper.deleteByInfoId(infoId);
        List<Long> categoryIds = infoUpdateDTO.getCategoryIds();
        if (categoryIds != null && !categoryIds.isEmpty()) {
            //插入分类
            infoCateLinkMapper.insertBatch(infoId, categoryIds);
        }

        imageMapper.deleteByInfoId(infoId);
        imageMapper.insertBatch(infoId, imageUrls);

        stringRedisTemplate.delete(RedisConstant.CACHE_INFO_KEY + infoUpdateDTO.getId());
    }

    @Override
    public LostAndFoundInfoDetailVO getDetail(Long id) {
        String key = RedisConstant.CACHE_INFO_KEY + id;
        String infoJson = stringRedisTemplate.opsForValue().get(key);

        if (StrUtil.isNotBlank(infoJson)) {
            return JSONUtil.toBean(infoJson, LostAndFoundInfoDetailVO.class);
        }

        LostAndFoundInfoDetailVO lostAndFoundInfoDetailVO = new LostAndFoundInfoDetailVO();
        LostAndFoundInfo lostAndFoundInfo = lostAndFoundInfoMapper.getById(id);
        BeanUtils.copyProperties(lostAndFoundInfo, lostAndFoundInfoDetailVO);

        List<String> images = imageMapper.getUrlByInfoId(id);
        lostAndFoundInfoDetailVO.setImages(images);

        List<Category> categories = infoCateLinkMapper.getByInfoId(id);
        lostAndFoundInfoDetailVO.setCategories(categories);

        User user = userMapper.getById(lostAndFoundInfo.getUserId());
        lostAndFoundInfoDetailVO.setUsername(user.getUsername());
        lostAndFoundInfoDetailVO.setAvatarPath(user.getAvatarPath());

        stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(lostAndFoundInfoDetailVO), RedisConstant.CACHE_INFO_TTL, TimeUnit.MINUTES);

        return lostAndFoundInfoDetailVO;
    }

    @Transactional
    @Override
    public void delete(Long id) {
        commentMapper.deleteByInfoId(id);
        likeMapper.deleteByInfoId(id);
        infoCateLinkMapper.deleteByInfoId(id);
        imageMapper.deleteByInfoId(id);
        lostAndFoundInfoMapper.deleteById(id);

        stringRedisTemplate.delete(RedisConstant.CACHE_INFO_KEY + id);
    }

    @Override
    public void updateStatus(Long id) {
        if (!lostAndFoundInfoMapper.getById(id).getUserId().equals(BaseContext.getCurrentId())) {
            throw new PermissionsExceededException(MessageConstant.PERMISSION_EXCEEDED);
        }
        LostAndFoundInfo lostAndFoundInfo = LostAndFoundInfo.builder().id(id).status(StatusConstant.RESOLVED).build();
        lostAndFoundInfoMapper.update(lostAndFoundInfo);

        stringRedisTemplate.delete(RedisConstant.CACHE_INFO_KEY + id);
    }

    @Override
    public Long getLostInfoTotal() {
        return lostAndFoundInfoMapper.getLostInfoTotal();
    }

    @Override
    public Long getFoundInfoTotal() {
        return lostAndFoundInfoMapper.getFoundInfoTotal();
    }

    @Override
    public Long getResolvedInfoTotal() {
        return lostAndFoundInfoMapper.getResolvedInfoTotal();
    }

    @Override
    public Long getUnresolvedInfoTotal() {
        return lostAndFoundInfoMapper.getUnresolvedInfoTotal();
    }

}
